package model

import (
	"easyVolunteer/utils/code"
	"easyVolunteer/utils/errno"
	"fmt"
	"gorm.io/gorm"
	"log"
)

// Activity https://github.com/go-playground/validator/blob/master/README.md#strings 数据验证文档
type Activity struct {
	Start      string         `gorm:"type:DATETIME;NOT NULL;comment:活动开始时间" json:"startTime" validate:"required" label:"开始时间"`
	End        string         `gorm:"type:DATETIME;NOT NULL;comment:活动结束时间" json:"endTime" validate:"required" label:"结束时间"`
	ActivityID uint64         `gorm:"primaryKey;type:BIGINT;comment:活动唯一ID; foreignKey" json:"activityID"`
	Duration   float32        `gorm:"NOT NULL;comment:活动持续时间" json:"duration" validate:"required,min=1,max=100"`
	OwnerID    string         `gorm:"type:BIGINT;NOT NULL;comment:活动创建者ID" json:"ownerID" validate:"required,len=10" label:"活动创建者ID"`
	Limits     uint8          `gorm:"type:INT;NOT NULL;comment: 活动限定人数" json:"limits" validate:"required,min=1,max=200"`
	Stock      uint8          `gorm:"type:TINYINT;NOT NULL;comment: 剩余招募名额" validate:"-"`
	Status     int            `gorm:"type:INT;NOT NULL;comment:活动状态码" json:"status" validate:"-"`
	Location   string         `gorm:"type:varchar(60);NOT NULL;comment:活动地点" json:"location" validate:"required,min=2,max=30" label:"活动地点"`
	Name       string         `gorm:"type:varchar(20);NOT NULL;comment:活动名称" json:"activityName" validate:"required,min=2,max=30" label:"活动名称"`
	Range      string         `gorm:"type:varchar(10);NOT NULL;DEFAULT:-;comment:活动招募范围" json:"range" validate:"-" label:"活动招募范围"`
	Comments   string         `gorm:"type:varchar(100);NOT NULL;comment:活动详情" json:"comments"  validate:"min=2,max=100"`
	Users      []User         `gorm:"many2many:activities_users;references:user_id" json:"-"`
	DeletedAt  gorm.DeletedAt `json:"-"`
}

// GetActivities 查询活动列表
func GetActivities(pageNum, pageSize, status int) ([]Activity, *errno.Errno) {
	var activities []Activity
	err := globalDb.Select([]string{"activity_id", "owner_id", "start", "end", "duration", "limits", "status", "stock", "location", "comments", "name"}).
		Where("status = ?", status).
		Limit(pageSize).
		Offset((pageNum - 1) * pageSize).
		Find(&activities).Error

	if err != nil {
		log.Println("查询活动列表失败,err", err)
		return nil, errno.ErrDatabase
	}
	return activities, errno.OK
}

// CreateActivity 添加活动
func CreateActivity(activity *Activity) *errno.Errno {
	err := globalDb.Create(activity).Error
	if err != nil {
		log.Println("添加活动失败,err", err)
		return errno.ErrDatabase
	}
	return errno.OK
}

// CancelActivity 取消活动
func CancelActivity(activityID uint64) *errno.Errno {
	err := ChangeActivityStatus(activityID, code.ActivityCancel)
	if err != nil {
		log.Println("取消活动失败")
		return errno.ErrDatabase
	}
	return errno.OK
}

// FinishActivity 完成活动，改变活动状态并把时长刷新到用户
func FinishActivity(activityID uint64) *errno.Errno {
	err := ChangeActivityStatus(activityID, code.ActivityFinished)
	if err != errno.OK {

		log.Println("设置完成活动失败")
		return err
	}
	err = SyncSingleActivity(activityID)
	if err != errno.OK {
		return err
	}
	return errno.OK
}

// ChangeActivityStatus 更改活动状态, status 为将要变更的状态
// 不检查实际操作的合法性，需要自行在调用时设置逻辑检查
func ChangeActivityStatus(activityID uint64, status int) *errno.Errno {
	var activity Activity
	activity.ActivityID = activityID
	exist := CheckActivityExist(activityID)
	if !exist {
		return errno.ErrActivityNotExist
	}
	err := globalDb.Model(&activity).Update("status", status).Error
	if err != nil {
		return errno.ErrDatabase
	}
	return errno.OK
}

// GetActivityInfo 获取某一个活动的详情
func GetActivityInfo(activityID uint64) (Activity, *errno.Errno) {
	var activity Activity
	//exist := CheckActivityExist(activityID)
	//if !exist {
	//	return Activity{}, errno.ErrActivityNotExist
	//}

	// 避免查找全部字段，查找所需要的字段
	err := globalDb.Select([]string{"activity_id", "owner_id", "start", "end", "duration", "limits", "stock", "status", "location", "comments", "range"}).First(&activity, activityID).Error
	if err != nil {
		log.Println("获取活动详情出错, err", err)
		return Activity{}, errno.ErrDatabase
	}

	//获取成功
	return activity, errno.OK
}

// CheckActivityExist 检查某一个活动是否存在,存在返回 true，不存在返回 false
func CheckActivityExist(activityId uint64) bool {
	var activity Activity
	err := globalDb.Select("activity_id").First(&activity, activityId).Error
	if err == gorm.ErrRecordNotFound {
		return false //活动不存在
	}
	return true
}

// GetVolunteers 获取某个活动下的所有志愿者
func GetVolunteers(activityID uint64) ([]User, *errno.Errno) {
	// TODO 多表连接 orm 操作
	//var activity Activity
	exist := CheckActivityExist(activityID)
	if !exist {
		return nil, errno.ErrActivityNotExist
	}
	var users []User
	a := Activity{ActivityID: activityID}

	err := globalDb.Model(&a).
		Preload("UserInfo").
		Association("Users").
		Find(&users)

	if err != nil {
		log.Println("获取某个活动下的所有志愿者失败 ,err", err)
		return nil, errno.ErrDatabase
	}

	return users, errno.OK //查找成功
}

// AllOwnedActivity 获得该用户创建的所有活动
func AllOwnedActivity(ownerId string) ([]Activity, *errno.Errno) {

	var activities []Activity

	_ = globalDb.Omit("deleted_at").Where(&Activity{OwnerID: ownerId}).Find(&activities)

	return activities, errno.OK
}

// GetActivityLimits 查询某一活动的限制人数
func GetActivityLimits(activityID uint64) (uint8, *errno.Errno) {
	a := Activity{}
	row := globalDb.Select("limits").First(&a, activityID).RowsAffected
	if row == 0 {
		return 0, errno.ErrActivityNotExist
	}
	return a.Limits, errno.OK
}

// SyncSingleActivity 把某一个活动的时长刷新到用户的记录里面
func SyncSingleActivity(activityID uint64) *errno.Errno {
	users, err := GetVolunteers(activityID)
	if err != errno.OK {
		return err
	}
	a := Activity{ActivityID: activityID}
	res := globalDb.Select("duration").First(&a, a.ActivityID).Error
	if res != nil {
		fmt.Println(err)
	}
	for _, u := range users {
		u.TotalHours += a.Duration
		globalDb.Model(&User{UserID: u.UserID}).Update("total_hours", u.TotalHours)
	}
	return errno.OK
}

// GetActivityRange 查询活动范围
func GetActivityRange(activityID uint64) (string, *errno.Errno) {
	a := Activity{ActivityID: activityID}
	err := globalDb.Model(&a).Select("range").First(&a).Error
	if err != nil {
		return "", errno.ErrDatabase
	}
	return a.Range, errno.OK
}

// GetActivityStock 查询活动剩余库存
func GetActivityStock(activityID uint64) (uint8, *errno.Errno) {
	var a Activity
	err := globalDb.Model(&activityID).Select("stock").First(&a).Error
	if err != nil {
		return 0, errno.ErrDatabase
	}
	return a.Stock, errno.OK
}

// GetActivityCoreInfo 活动库存，招募范围，以及活动状态
func GetActivityCoreInfo(activityID uint64) (Activity, *errno.Errno) {
	var a Activity
	err := globalDb.Model(&a).Select([]string{"stock", "range", "status"}).First(&a).Error
	if err != nil {
		return Activity{}, errno.ErrDatabase
	}
	return a, errno.OK
}

func FindActivityInfo(actID uint64, infos ...string) (Activity, *errno.Errno) {
	var a Activity
	err := globalDb.Model(&Activity{}).Select(infos).First(&a, actID).Error
	if err != nil {
		fmt.Println(err)
		return Activity{}, errno.ErrDatabase
	}

	return a, errno.OK
}

// Count 获取计数
func Count(a Activity) (int64, *errno.Errno) {
	var count int64 = 0
	err := globalDb.Model(&Activity{}).Where(&a).Count(&count).Error
	if err != nil {
		return 0, errno.ErrDatabase
	}
	return count, errno.OK
}
